package com.whcoding.test.common;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.whcoding.test.annotion.FieldAnnotation;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @program: spring-boot-learning
 * @description:  字段比对
 * @author: whcoding
 * @create: 2022-09-06 14:54
 **/
public class CompareFieldsUtils {


	/**
	 * 获取带注解的属性 并且封装数据返回
	 *
	 * @param clazz
	 * @return Map<String, Map<String, String>>
	 */
	public static Map<String, Map<String, String>> getColumnNameForClass(Class clazz) {
		Map<String, Map<String, String>> map = new HashMap<>();
		Field[] fields = FieldUtils.getAllFields(clazz);

		// FieldUtils获取带注解的属性 这个可以获取父类
		// Field[] fields = FieldUtils.getFieldsWithAnnotation(clazz,
		// FieldAnnotation.class);
		for (Field field : fields) {
			// 属性名
			String name = field.getName();
			// 判断属性是否有这个注解
			if (field.isAnnotationPresent(FieldAnnotation.class)) {
				FieldAnnotation annotation = field.getAnnotation(FieldAnnotation.class);
				String fieldName = annotation != null ? annotation.fieldName() : "";
				String dataColumn = annotation != null ? annotation.dataColumn() : "";

				// 封装数据
				Map<String, String> tempMap = new HashMap<>();
				tempMap.put("fieldName", fieldName);
				tempMap.put("dataColumn", dataColumn);

				map.put(name, tempMap);
			}
		}
		return map;
	}

	/**
	 * 比较两个实体属性值，返回一个以有差异的属性值的集合
	 *
	 * @param oldObject
	 *            进行属性比较的对象1
	 * @param newObject
	 *            进行属性比较的对象2
	 * @return List<Map<String, Object>>
	 */
	@SneakyThrows
	public static  <T> List<Map<String, Object>> compareFields(T oldObject, T newObject) {
		List<Map<String, Object>> list = new ArrayList<>();

		if (oldObject != null && newObject != null) {
			// 不参与对比的字段
			List<String> cloumList = new ArrayList<>(Arrays.asList(
					new String[] { "createdId", "createdBy", "createdAt", "modifiedId", "modifiedBy", "modifiedAt" }));

			// 只有两个对象都是同一类型的才有可比性
			if (oldObject.getClass() == newObject.getClass()) {
				Class clazz = oldObject.getClass();
				// 获取属性和属性翻译注解的对应关系
				// Map<String, Map<String, String>> columnNameMap = getColumnNameForClass(clazz);

				// 获取所有属性
				Field[] fields = FieldUtils.getAllFields(clazz);

				for (Field field : fields) {
					Map<String, Object> map = new HashMap<>();
					// 如果成员变量为private,需要设置Accessible为true
					field.setAccessible(true);

					// 属性
					String name = field.getName();
					// 部分属性不参与属性对比
					if (cloumList.indexOf(name) != -1) {
						continue;
					}

					// 获取属性的值
					Object oldValue = field.get(oldObject);
					Object newValue = field.get(newObject);

					String fieldName = null;
					String dataColumn = null;

					// 判断属性是否有这个注解
					if (field.isAnnotationPresent(FieldAnnotation.class)) {
						FieldAnnotation annotation = field.getAnnotation(FieldAnnotation.class);
						fieldName = annotation != null ? annotation.fieldName() : "";
						dataColumn = annotation != null ? annotation.dataColumn() : "";
					}

					// 如果属性是List则跳过这个属性
					if (oldValue instanceof List || newValue instanceof List) {
						continue;
					}
					// 如果属性是时间
					if (oldValue instanceof Date || newValue instanceof Date) {
						oldValue = DateUtil.format((Date) oldValue, DatePattern.NORM_DATETIME_PATTERN);
						newValue = DateUtil.format((Date) newValue, DatePattern.NORM_DATETIME_PATTERN);
					}
					// 如果属性是字符串,需要判断null与空串"",同一个类同一个属性,类型肯定相同
					if (oldValue instanceof String || newValue instanceof String) {
						if (StringUtils.isBlank((CharSequence) oldValue) && StringUtils.isBlank((CharSequence) newValue)) {
							continue;
						}
					}
					// 正常属性
					if (oldValue == null && newValue == null) {
						continue;
					} else if (oldValue == null && newValue != null) {
						map.put("modifiedField", dataColumn);
						map.put("modifiedFieldName", fieldName);
						map.put("oldValue", null);
						map.put("newValue", newValue);
						list.add(map);
						continue;
					} else if (oldValue != null && newValue == null){
						map.put("modifiedField", dataColumn);
						map.put("modifiedFieldName", fieldName);
						map.put("oldValue", oldValue);
						map.put("newValue", null);
						list.add(map);
						continue;
					} else {
						if (!oldValue.equals(newValue)) {
							// 比较这两个值是否相等,不等就可以放入map了
							map.put("modifiedField", dataColumn);
							map.put("modifiedFieldName", fieldName);
							map.put("oldValue", oldValue);
							map.put("newValue", newValue);
							list.add(map);
						}
					}
				}
			}
		}
		return list;
	}

}
